package com.hex.es.service.impl;

import com.github.vanroy.springdata.jest.JestElasticsearchTemplate;
import com.github.vanroy.springdata.jest.mapper.JestResultsExtractor;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.hex.es.annotation.EsBuildParamTypeInfo;
import com.hex.es.aop.AbstractEsAop;
import com.hex.es.service.ReturnSearchInterface;
import io.searchbox.core.SearchResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @description: 分局聚合型List返回类型处理类
 * @author: Hex
 * @date: 2019/11/13 16:29
 */
@Slf4j
@Service
public class ReturnListGroupImpl extends AbstractEsAop implements ReturnSearchInterface {

    private final static SimpleDateFormat FORMATTER = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Resource
    private JestElasticsearchTemplate jestElasticsearchTemplate;

    @Resource
    private ReturnListImpl returnList;

    @Override
    public Object search(Method method, EsBuildParamTypeInfo esBuildParamTypeInfo, SearchQuery searchQuery) throws Exception {
        if (method.getReturnType() != List.class) {
            throw new RuntimeException("分组查询时返回类型必须为list");
        }
        returnList.search(method,esBuildParamTypeInfo,searchQuery);
        JsonObject jsonObject = jestElasticsearchTemplate.query(searchQuery, new JestResultsExtractor<JsonObject>() {
            @Override
            public JsonObject extract(SearchResult response) {
                return response.getJsonObject();
            }
        });
        JsonArray buckets = jsonObject.getAsJsonObject("aggregations").getAsJsonObject(lineToHump(esBuildParamTypeInfo.groupByFieldName())).getAsJsonArray("buckets");

        String[] statisticsAnotherName = esBuildParamTypeInfo.statisticsAnotherName();
        Class aClass = esBuildParamTypeInfo.resultType();
        List list = new ArrayList();

        for (int i=0;i<buckets.size();i++) {
            Object returnObject = aClass.newInstance();
            JsonElement jsonElement = buckets.get(i);
            for (String anotherName : statisticsAnotherName) {
                JsonPrimitive value = jsonElement.getAsJsonObject().getAsJsonObject(anotherName).getAsJsonPrimitive("value");

                Field[] fields = aClass.getDeclaredFields();
                for (Field field : fields) {
                    if (field.getName().equals(anotherName)) {
                        Class<?> type = field.getType();
                        setFieldValue(aClass, returnObject, value, field, type);
                    } else if (field.getName().equals(lineToHump(esBuildParamTypeInfo.groupByFieldName()))) {
                        Class<?> type = field.getType();
                        setFieldValue(aClass,returnObject,jsonElement.getAsJsonObject().getAsJsonPrimitive("key_as_string").getAsJsonPrimitive(),field,type);
                    }
                }
            }
            list.add(returnObject);
        }
        return list;
    }

    @Override
    public Boolean check(Method method, EsBuildParamTypeInfo esBuildParamTypeInfo) {
        return StringUtils.isNotEmpty(esBuildParamTypeInfo.groupByFieldName());
    }

    @Override
    public int getOrder() {
        return 10;
    }

    private void setFieldValue(Class aClass, Object returnObject, JsonPrimitive value, Field field, Class<?> type) throws IllegalAccessException, ParseException {
        field.setAccessible(true);
        if (type.equals(Integer.class)) {
            field.set(returnObject, value.getAsInt());
        } else if (type.equals(Float.class)) {
            field.set(returnObject, value.getAsFloat());
        } else if (type.equals(Double.class)) {
            field.set(returnObject, value.getAsDouble());
        } else if (type.equals(Long.class)) {
            field.set(returnObject, value.getAsLong());
        } else if (type.equals(Byte.class)) {
            field.set(returnObject, value.getAsByte());
        } else if (type.equals(Character.class)) {
            field.set(returnObject, value.getAsCharacter());
        } else if (type.equals(Boolean.class)) {
            field.set(returnObject, value.getAsBoolean());
        } else if (type.equals(String.class)) {
            field.set(returnObject, value.getAsString());
        } else if (type.equals(BigDecimal.class)) {
            field.set(returnObject, value.getAsBigDecimal());
        }  else if (type.equals(Date.class)) {
            String asString = value.getAsString();
            field.set(returnObject, FORMATTER.parse(asString));
        } else {
            log.error("{},class field is not mapping,fieldName:{}",aClass,field.getName());
        }
    }
}
